﻿using DataType;
using DataType.CustomEnumType;
using DataType.JudgeResults;
using DataType.MessageType;
using MapCalclator;
using OprsSimulator.OprAttributes;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace OprsSimulator.Operators
{
    public class InfantryOpr : IOperator, ICommonAttris, IAttackAttris, IMoveAttris, IStateAttris, IReconnaissanceAttris, IDefendAttris
    {
        //ICommonAttris
        private int obj_id;
        private string name;
        private Color color;
        private OprType type;
        private OprSubType sub_type;
        private int value;
        private int blood;
        private int max_blood;

        public int ObjID { get => obj_id; }
        public string Name { get => name; }

        public Color Color { get => color; }

        public OprType Type { get => type; }

        public OprSubType Subtype { get => sub_type; }

        public int Value { get => value; }

        public int Blood { get => blood; set => blood = value; }

        public int MaxBlood { get => max_blood; }

        //IAttackAttris
        private bool a1;
        private List<WeaponType> carry_weapon_ids = new List<WeaponType>();
        private Dictionary<BulletType, int> remain_bullet_nums = new Dictionary<BulletType, int>();
        private Dictionary<BulletType, int> remain_bullet_nums_bk = new Dictionary<BulletType, int>();
        private bool guide_ability;
        private int weapon_cool_time;
        private int weapon_unfold_time;
        private int weapon_unfold_state;
        public bool A1 { get => a1; }

        public List<WeaponType> CarryWeaponIDs { get => carry_weapon_ids; }

        public Dictionary<BulletType, int> RemainBulletNums { get => remain_bullet_nums; set => remain_bullet_nums = value; }
        public Dictionary<BulletType, int> RemainBulletNumsBK { get => remain_bullet_nums_bk; set => remain_bullet_nums_bk = value; }

        public bool GuideAbility { get => guide_ability; }

        public int WeaponCoolTime { get => weapon_cool_time; set => weapon_cool_time = value; }
        public int WeaponUnfoldTime { get => weapon_unfold_time; set => weapon_unfold_time = value; }
        public int WeaponUnfoldState { get => weapon_unfold_state; set => weapon_unfold_state = value; }

        //IMoveAttris
        private int basic_speed;
        private MoveStateType move_state;
        private int cur_hex;
        private float cur_pos;
        private int speed;
        private int move_to_stop_remain_time;
        private bool can_to_move;
        private bool flag_force_stop;
        private bool stop;
        private List<int> move_path;
        private int tire;
        private int tire_accumulate_time;
        private bool on_board;
        private int car;
        private int launcher;
        private int get_on_remain_time;
        private List<int> get_on_partner_id;
        private int get_off_remain_time;
        private List<int> get_off_partner_id;
        private int change_state_remain_time;
        private MoveStateType target_state;

        public int BasicSpeed { get => basic_speed; }

        public MoveStateType MoveState { get => move_state; set => move_state = value; }
        public int CurHex { get => cur_hex; set => cur_hex = value; }
        public float CurPos { get => cur_pos; set => cur_pos = value; }
        public int Speed { get => speed; set => speed = value; }
        public int MoveToStopRemainTime { get => move_to_stop_remain_time; set => move_to_stop_remain_time = value; }
        public bool CanToMove { get => can_to_move; set => can_to_move = value; }
        public bool FlagForceStop { get => flag_force_stop; set => flag_force_stop = value; }
        public bool Stop { get => stop; set => stop = value; }
        public List<int> MovePath { get => move_path; set => move_path = value; }
        public int Tire { get => tire; set => tire = value; }
        public int TireAccumulateTime { get => tire_accumulate_time; set => tire_accumulate_time = value; }
        public bool OnBoard { get => on_board; set => on_board = value; }
        public int Car { get => car; set => car = value; }
        public int Launcher { get => launcher; set => launcher = value; }
        public int GetOnRemainTime { get => get_on_remain_time; set => get_on_remain_time = value; }
        public List<int> GetOnPartnerId { get => get_on_partner_id; set => get_on_partner_id = value; }
        public int GetOffRemainTime { get => get_off_remain_time; set => get_off_remain_time = value; }
        public List<int> GetOffPartnerId { get => get_off_partner_id; set => get_off_partner_id = value; }
        public int ChangeStateRemainTime { get => change_state_remain_time; set => change_state_remain_time = value; }
        public MoveStateType TargetState { get => target_state; set => target_state = value; }
        //IStateAttris
        private bool stack;
        private bool keep;
        private int keep_remain_time;
        private bool lose_control;
        private int alive_remain_time;
        public bool Stack { get => stack; set => stack = value; }
        public bool Keep { get => keep; set => keep = value; }
        public int KeepRemainTime { get => keep_remain_time; set => keep_remain_time = value; }
        public bool LoseControl { get => lose_control; set => lose_control = value; }
        public int AliveRemainTime { get => alive_remain_time; set => alive_remain_time = value; }
        //IReconnaissanceAttris
        private Dictionary<OprSubType, int> observe_distance;
        private List<int> see_enemy_bop_ids;
        public Dictionary<OprSubType, int> ObserveDistance { get => observe_distance; }

        public List<int> SeeEnemyBopIDs { get => see_enemy_bop_ids; set => see_enemy_bop_ids = value; }
        //IDefendAttris
        private ArmorType armor;
        public ArmorType Armor { get => armor; set => armor = value; }

        public void SetUp(OperatorMsg operatorMsg)
        {
            //ICommonAttris
            obj_id = operatorMsg.obj_id;
            name = operatorMsg.name;
            color = (Color)operatorMsg.color;
            type = (OprType)operatorMsg.type;
            sub_type = (OprSubType)operatorMsg.sub_type;
            value = operatorMsg.value;
            blood = operatorMsg.blood;
            max_blood = operatorMsg.max_blood;
            //IAttackAttris
            a1 = operatorMsg.A1;
            foreach (int id in operatorMsg.carry_weapon_ids)
            {
                carry_weapon_ids.Add((WeaponType)id);
            }
            foreach (var remain_bullet_num in operatorMsg.remain_bullet_nums)
            {
                remain_bullet_nums.Add((BulletType)remain_bullet_num.Key, remain_bullet_num.Value);
            }
            foreach (var remain_bullet_num_bk in operatorMsg.remain_bullet_nums_bk ?? new Dictionary<int, int>())
            {
                remain_bullet_nums_bk.Add((BulletType)remain_bullet_num_bk.Key, remain_bullet_num_bk.Value);
            }
            guide_ability = operatorMsg.guide_ability;
            weapon_cool_time = operatorMsg.weapon_cool_time;
            weapon_unfold_time = operatorMsg.weapon_unfold_time;
            weapon_unfold_state = operatorMsg.weapon_unfold_state;
            //IMoveAttris
            basic_speed = operatorMsg.basic_speed;
            move_state = (MoveStateType)operatorMsg.move_state;
            cur_hex = operatorMsg.cur_hex;
            cur_pos = operatorMsg.cur_pos;
            speed = operatorMsg.speed;
            move_to_stop_remain_time = operatorMsg.move_to_stop_remain_time;
            can_to_move = operatorMsg.can_to_move;
            flag_force_stop = operatorMsg.flag_force_stop;
            stop = operatorMsg.stop;
            move_path = operatorMsg.move_path;
            tire = operatorMsg.tire;
            tire_accumulate_time = operatorMsg.tire_accumulate_time;
            on_board = operatorMsg.on_board;
            car = operatorMsg.car ?? -1;
            launcher = operatorMsg.launcher ?? -1;
            get_on_remain_time = operatorMsg.get_on_remain_time;
            get_on_partner_id = operatorMsg.get_on_partner_id;
            get_off_remain_time = operatorMsg.get_off_remain_time;
            get_off_partner_id = operatorMsg.get_off_partner_id;
            change_state_remain_time = operatorMsg.change_state_remain_time;
            target_state = (MoveStateType)operatorMsg.target_state;
            //IStateAttris
            stack = operatorMsg.stack;
            keep = operatorMsg.keep;
            keep_remain_time = operatorMsg.keep_remain_time;
            lose_control = operatorMsg.lose_control;
            alive_remain_time = operatorMsg.alive_remain_time;
            //IReconnaissanceAttris
            if (operatorMsg.observe_distance == null)
            {
                observe_distance = new Dictionary<OprSubType, int>
                {
                    {OprSubType.Tank, 25},
                    {OprSubType.IFV, 25},
                    {OprSubType.Infantry, 10},
                    {OprSubType.Artillery, 10},
                    {OprSubType.UGV, 25},
                    {OprSubType.Drone, 1},
                    {OprSubType.Helicopter, 25},
                    {OprSubType.CruisingMissile, 1},
                };
            }
            else
            {
                foreach (var od in operatorMsg.observe_distance)
                {
                    observe_distance.Add((OprSubType)od.Key, od.Value);
                }
            }
            see_enemy_bop_ids = operatorMsg.see_enemy_bop_ids ?? new List<int>();
            //IDefendAttris
            armor = (ArmorType)operatorMsg.armor;
        }
        public void UpdataStandaloneAttris(List<IJudgeResult> judge_results, Map map)
        {
            foreach (IJudgeResult judge_result in judge_results)
            {
                if (judge_result.ActionType == ActionType.Shoot || judge_result.ActionType == ActionType.GuideShoot)  // 直瞄射击、引导射击、被射击
                {
                    UpdataShootAttris(judge_result);
                }
                else
                {
                    if (!judge_result.IsSuccess) continue;// 裁决没有执行成功，跳过

                    if (judge_result.ActionType == ActionType.GetOff)// 下车裁决结果更新
                    {
                        UpdataGetOffAttris(judge_result);// 作为下车的目标
                    }
                    else
                    {
                        if (judge_result.ObjID != obj_id) continue;// 不是此算子执行的动作的裁决结果，跳过
                        if (judge_result.ActionType == ActionType.Move) UpdataMoveAttris(judge_result, map);// 机动裁决结果更新
                        else if (judge_result.ActionType == ActionType.ChangeState) UpdataChangeStateAttris(judge_result);// 切换状态裁决结果更新
                        else if (judge_result.ActionType == ActionType.StopMove) UpdataStopMoveAttris(judge_result);// 停止机动裁决结果更新
                        else if (judge_result.ActionType == ActionType.GetOn) UpdataGetOnAttris(judge_result);// 上车裁决结果更新
                    }
                }
            }
            PutForwardObservation(map);// 更新持续性动作，如机动和各种倒计时等
        }

        public void UpdateAssociatedAttris(List<IOperator> oprs, List<IOperator> passengers, Map map)
        {
            if (!on_board)// 如果不在车上
            {
                UpdataStackAttris(oprs);// 更新堆叠状态
                UpdataSeeEnemyAttris(oprs, map);// 更新观察敌方算子属性
                JudgeMoveObstruction(oprs);// 检查算子机动是否会被阻塞
            }
            GetOnAndOffMonitor(oprs);// 检查上下车的对象的状态
        }
        public Dictionary<int, List<ActionMsg>> ConfirmValidActions(List<OperatorMsg> oprs, CityMsg[] cities, Map map, ShootJudgeTable shootJudgeTable, List<IOperator> passengers)
        {
            Dictionary<int, List<ActionMsg>> individualValidActions = new Dictionary<int, List<ActionMsg>>();

            if (on_board) return individualValidActions;// 如果在车上，则没有可以执行的动作

            // 判断算子是否能机动
            bool move_flag = true;  // 能够机动的标识
            List<ActionMsg> move_action = new List<ActionMsg>();// 新建机动动作集合
            if (speed > 0) move_flag = false;   //未停下的算子不可机动
            if (get_off_remain_time > 0 || get_on_remain_time > 0) move_flag = false;   //上下车过程中不可执行其它命令
            if (!can_to_move && move_to_stop_remain_time > 0) move_flag = false;// 如果在停止机动的惩罚中，不可以机动
            else if (change_state_remain_time > 0)  // 如果正处于状态转换过程中
            {
                if (target_state == MoveStateType.Shelt) move_flag = false;// 在转掩蔽，不可以机动
            }
            if (/*move_state == MoveStateType.RushLevel1 && */tire > 1) move_flag = false;  //二级疲劳不能机动
            if (move_state == MoveStateType.RushLevel2 && tire > 0) move_flag = false;  //二级冲锋一级疲劳
            if (keep) move_flag = false;    //被压制不可机动
            if (move_flag)// 如果可以机动
            {
                move_action.Add(new ActionMsg { type = (int)ActionType.Move, obj_id = obj_id });// 设置动作类型、算子id
                individualValidActions.Add((int)ActionType.Move, move_action);// 动作集合添加进合法动作以该动作类型为键的值中
            }

            // 判断算子是否能射击
            bool shoot_flag = true;  // 不能射击的标识
            List<ActionMsg> shoot_action = new List<ActionMsg>();// 新建直瞄射击动作集合
            if (weapon_cool_time > 0) shoot_flag = false;// 如果武器在冷却，不能射击
            else if (keep) shoot_flag = false;  // 被压制不可射击
            else if (get_off_remain_time > 0 || get_on_remain_time > 0) shoot_flag = false;   //上下车过程中不可执行其它命令
            else if (!a1 && target_state == MoveStateType.Shelt && change_state_remain_time > 0) shoot_flag = false;// 没有行进间射击能力，且在转掩蔽中，不能射击
            else if (!a1 && speed > 0) shoot_flag = false;// 没有行进间射击能力，且正在机动，不能射击
            else if (!a1 && !stop) shoot_flag = false;// 没有行进间射击能力，且不处于静止状态，不可以射击
            else if (see_enemy_bop_ids.Count == 0) shoot_flag = false;  // 视野范围内没有敌方算子
            else
            {
                for (int i = 0; i < see_enemy_bop_ids.Count(); i++)
                //foreach (int enemy_id in see_enemy_bop_ids)
                {
                    int enemy_id = see_enemy_bop_ids[i];
                    // 逐个判断是否能对enemy_id的敌方算子实施射击
                    OperatorMsg enemy;
                    foreach (OperatorMsg oper in oprs)
                    {
                        if (oper.obj_id == enemy_id)// 根据id找到态势中的算子
                        {
                            enemy = oper;// 赋值
                            foreach (WeaponType weapon_id in carry_weapon_ids)// 判断携带的全部武器
                            {

                                bool can_see = map.CanSeeTerrain(type, (OprType)enemy.type, cur_hex, enemy.cur_hex, (OprSubType)enemy.sub_type, observe_distance, (MoveStateType)enemy.move_state);// 可视
                                int distance = map.GetDistance(cur_hex, enemy.cur_hex);// 距离
                                int attack_level = shootJudgeTable.CalcAttackLevel(can_see, remain_bullet_nums, weapon_id, (OprType)enemy.type, distance, blood);// 攻击等级
                                if (attack_level > 0)// 如果攻击等级大于0
                                {
                                    shoot_action.Add(// 创建直瞄射击动作，并添加
                                        new ActionMsg
                                        {
                                            type = (int)ActionType.Shoot,// 动作类型
                                            obj_id = obj_id,// 算子id
                                            target_obj_id = enemy_id,// 射击目标id
                                            weapon_id = (int)weapon_id,// 武器id
                                            attack_level = attack_level// 攻击等级
                                        }
                                        );
                                }
                            }
                        }
                    }
                }
            }
            if (shoot_flag)// 如果可以射击
            {
                if (shoot_action.Count > 0)// 如果有可以执行的射击动作
                {
                    individualValidActions.Add((int)ActionType.Shoot, shoot_action);// 动作集合添加进合法动作以该动作类型为键的值中
                }
            }

            // 判断是否能夺控
            foreach (CityMsg city in cities)// 遍历全部夺控点
            {
                if (cur_hex == city.coord && (int)color != city.flag)// 如果本算子位置上有不是本方的夺控点
                {
                    bool enemy_neighbor = false;// 检查周围有无敌方地面算子
                    foreach (OperatorMsg ob in oprs)
                    {
                        if (ob.color == (int)color) continue;// 我方的算子，跳过
                        if (ob.type != (int)OprType.Airplane && ob.type != (int)OprType.Fortification)// 是敌方的地面算子
                        {
                            if (map[city.coord / 100, city.coord % 100].neighbors.Contains(ob.cur_hex) || ob.cur_hex == city.coord)// 如果敌方的地面算子在夺控点位置，或者邻格
                            {
                                enemy_neighbor = true;// 有敌方地面算子
                                break;
                            }
                        }
                    }

                    if (!enemy_neighbor)  // 能夺控的条件：夺控点周围不能由敌人
                    {
                        List<ActionMsg> occupy_action = new List<ActionMsg>();// 创建夺控动作
                        occupy_action.Add(
                            new ActionMsg { type = (int)ActionType.Occupy, obj_id = obj_id }// 动作类型、算子id
                            );
                        individualValidActions.Add((int)ActionType.Occupy, occupy_action);// 动作集合添加进合法动作以该动作类型为键的值中
                        break;
                    }
                }
            }


            // 判断是否能切换状态
            List<ActionMsg> change_state_action = new List<ActionMsg>();// 新建切换状态动作集合
            // 1.判断能否转正常机动状态    // 如果算子在一级冲锋、二级冲锋或者掩蔽状态
            if (move_state == MoveStateType.Shelt || move_state == MoveStateType.RushLevel1 || move_state == MoveStateType.RushLevel2)
            {
                if (change_state_remain_time <= 0 && get_on_remain_time <= 0 && get_off_remain_time <= 0)  // 判断是否处于正常状态
                {
                    if (stop | speed <= 0.0)  // 行军状态下，只要停下来就能切换成正常机动状态
                    {
                        change_state_action.Add(// 添加动作
                        new ActionMsg { type = (int)ActionType.ChangeState, obj_id = obj_id, target_state = (int)MoveStateType.Normal }// 动作类型、算子id、目标状态
                        );
                    }
                }
            }
            // 2.判断能否转一级冲锋状态    // 如果算子在正常机动、二级冲锋或者掩蔽状态
            if (move_state == MoveStateType.Shelt || move_state == MoveStateType.Normal || move_state == MoveStateType.RushLevel2)
            {
                if (change_state_remain_time <= 0 && get_on_remain_time <= 0 && get_off_remain_time <= 0)  // 判断是否处于正常状态
                {
                    if (!keep)// 没有被压制
                    {
                        if (stop | speed <= 0.0)  // 必须已经停下来了
                        {
                            change_state_action.Add(// 添加动作
                                new ActionMsg { type = (int)ActionType.ChangeState, obj_id = obj_id, target_state = (int)MoveStateType.RushLevel1 }// 动作类型、算子id、目标状态
                                );
                        }
                    }
                }
            }

            // 3.判断能否转二级冲锋状态    // 如果算子在正常机动、一级冲锋或者掩蔽状态
            if (move_state == MoveStateType.Shelt || move_state == MoveStateType.Normal || move_state == MoveStateType.RushLevel1)
            {
                if (change_state_remain_time <= 0 && get_on_remain_time <= 0 && get_off_remain_time <= 0)  // 判断是否处于正常状态
                {
                    if (!keep && tire < 1)// 没有被压制，且没有疲劳值
                    {
                        if (stop | speed <= 0.0)  // 必须已经停下来了
                        {
                            change_state_action.Add(// 添加动作
                                new ActionMsg { type = (int)ActionType.ChangeState, obj_id = obj_id, target_state = (int)MoveStateType.RushLevel2 }// 动作类型、算子id、目标状态
                                );
                        }
                    }
                }
            }

            // 3.判断能否转掩蔽状态  // 如果算子在正常机动、一级冲锋或者二级冲锋状态
            if (move_state == MoveStateType.Normal || move_state == MoveStateType.RushLevel1 || move_state == MoveStateType.RushLevel2)
            {
                if (!keep) // 不能处于压制状态
                {
                    if (change_state_remain_time <= 0 && get_on_remain_time <= 0 && get_off_remain_time <= 0)  // 判断是否处于正常状态
                    {
                        if (stop | speed <= 0.0)  // 必须已经停下来了
                        {
                            change_state_action.Add(// 添加动作
                                new ActionMsg { type = (int)ActionType.ChangeState, obj_id = obj_id, target_state = (int)MoveStateType.Shelt }// 动作类型、算子id、目标状态
                                );
                        }
                    }
                }
            }

            // 如果change_state_action不为空
            if (change_state_action.Count > 0) individualValidActions.Add((int)ActionType.ChangeState, change_state_action);// 切换状态动作集合添加进合法动作中

            // 判断能否停止机动
            if (speed > 0)// 正在机动
            {
                List<ActionMsg> stop_move_action = new List<ActionMsg>();// 新建停止机动动作集合
                stop_move_action.Add(new ActionMsg { type = (int)ActionType.StopMove, obj_id = obj_id });// 添加动作（动作类型、算子id
                individualValidActions.Add((int)ActionType.StopMove, stop_move_action);// 动作集合添加进合法动作以该动作类型为键的值中
            }

            //判断能否上车
            if (get_on_remain_time <= 0 && change_state_remain_time <= 0)// 没有在执行其他动作
            {
                if (stop && !keep)// 处于静止状态，且没有被压制
                {
                    List<ActionMsg> get_on_action = new List<ActionMsg>();// 新建上车动作集合
                    foreach (OperatorMsg opr in oprs)// 遍历算子
                    {
                        if (opr.valid_passenger_types == null || opr.obj_id == obj_id) continue;// 如果不能搭乘本算子，跳过
                        if (opr.cur_hex == cur_hex && opr.color == (int)color && opr.valid_passenger_types.Contains((int)sub_type))// 如果是位于同一位置的己方车辆，且可以搭乘本算子
                        {
                            if (opr.stop && !opr.keep && opr.move_state != (int)MoveStateType.March && opr.loading_capacity >= blood)// 如果车辆算子静止、没有被压制、没有在行军、且本算子没有超出车辆的最大搭乘能力
                            {
                                get_on_action.Add(new ActionMsg { type = (int)ActionType.GetOff, obj_id = obj_id, target_obj_id = opr.obj_id });// 添加动作（动作类型、算子id、车辆id
                            }
                        }
                    }                   
                    if (get_on_action.Count > 0) individualValidActions.Add((int)ActionType.GetOn, get_on_action);// 如果集合中有可以执行的动作，动作集合添加进合法动作以该动作类型为键的值中
                }
            }

            // 判断能否引导射击
            bool flagGuideShoot = true;// 可以引导射击的标志位
            List<ActionMsg> guide_shoot_action = new List<ActionMsg>();// 新建引导射击动作集合
            if (!guide_ability) flagGuideShoot = false;// 如果没有引导射击能力，不可以执行
            else if (!stop) flagGuideShoot = false;// 如果不处于静止状态，不可以执行
            else if (keep) flagGuideShoot = false;// 如果被压制，不可以执行
            else if (weapon_cool_time > 0) flagGuideShoot = false;// 如果引导射击75秒冷却中，不可以执行
            else if (change_state_remain_time > 0) flagGuideShoot = false;// 如果正在切换状态，不可以执行
            else if (get_off_remain_time > 0 || get_on_remain_time > 0) flagGuideShoot = false;// 如果正在上下车，不可以执行
            else if (on_board) flagGuideShoot = false;// 如果正在车上，不可以执行
            else if (launcher == -1) flagGuideShoot = false;// 如果没有所属的发射算子，不可以执行
            else if (see_enemy_bop_ids.Count > 0)
            {
                foreach (var opr in oprs)
                {
                    // 携带重型导弹
                    if (opr.obj_id != launcher || opr.carry_weapon_ids == null || opr.sub_type != (int)OprSubType.IFV)// 不是所属的战车，或者没有携带武器
                    {
                        continue;// 跳过
                    }
                    if (opr.carry_weapon_ids.Contains((int)WeaponType.HeavyMissile))// 如果所属战车携带了重型导弹
                    {
                        if (opr.weapon_cool_time > 0 || opr.weapon_unfold_time > 0 || opr.weapon_unfold_state == 0 || opr.change_state_remain_time > 0
                            || opr.get_off_remain_time > 0 || opr.get_on_remain_time > 0 || !opr.stop) break;// 如果战车武器在冷却，武器没展开，或者正在执行其他动作，结束判断

                        foreach (var enemy in oprs)// 寻找可以攻击的敌方
                        {
                            if (see_enemy_bop_ids.Contains(enemy.obj_id))// 如果本算子可以看见
                            {
                                bool can_see = true;
                                int distance = map.GetDistance(opr.cur_hex, enemy.cur_hex);// 战车与敌方算子的距离
                                int attack_level = shootJudgeTable.CalcAttackLevel(can_see, opr.remain_bullet_nums, WeaponType.HeavyMissile, enemy.type, distance, opr.blood);
                                if (attack_level > 0)// 如果攻击等级大于0
                                {
                                    guide_shoot_action.Add(// 创建引导射击动作，并添加
                                        new ActionMsg
                                        {
                                            type = (int)ActionType.GuideShoot,// 动作类型
                                            obj_id = obj_id,// 算子id
                                            guided_obj_id = opr.obj_id,// 被引导的战车id
                                            target_obj_id = enemy.obj_id,// 射击目标id
                                            weapon_id = (int)WeaponType.HeavyMissile,// 武器id
                                            attack_level = attack_level// 攻击等级
                                        }
                                        );
                                }
                            }
                        }
                    }
                }
            }
            if (flagGuideShoot)// 如果可以引导射击
            {
                if (guide_shoot_action.Count > 0)// 如果有可以执行的引导射击动作
                {
                    individualValidActions.Add((int)ActionType.GuideShoot, guide_shoot_action);// 动作集合添加进合法动作以该动作类型为键的值中
                }
            }

            return individualValidActions;
        }
        private void PutForwardObservation(Map map)
        {
            // 修改机动属性
            if (cur_pos > 0 && keep)  //机动过程中被压制，完成当前格机动后停止
            {
                float percetage = (float)speed / 3.6f / (float)map.Width;// 计算一个step移动了多远（speed是km/h，除3.6得到m/s，除六角格宽度（单位为米））
                cur_pos += percetage;
                if (cur_pos >= 1)  // 到达了下一格
                {
                    cur_pos = 0;
                    cur_hex = move_path[0];// 修改位置
                    move_path.RemoveAt(0);// 修改机动路径
                    if (move_state == MoveStateType.RushLevel1 || move_state == MoveStateType.RushLevel2) tire += 1;// 如果处于冲锋状态，增加疲劳值
                    if (tire > 0 && tire_accumulate_time <= 0) tire_accumulate_time = 76;// 此时是被压制，不能继续机动，所以判断如果有疲劳值就开始消去疲劳值的计时
                }
            }
            if (speed > 0 && move_path.Count > 0)  //没有被压制的时候，正常机动；或者是被压制但是完成了当前格的机动
            {
                bool canMoveFlag = true;// 判断能不能机动
                if (keep) canMoveFlag = false;// 如果被压制了，不能
                else if (tire == 1 && move_state == MoveStateType.RushLevel2) canMoveFlag = false;// 一级疲劳状态下不能实施二级冲锋
                else if (tire == 2) canMoveFlag = false;// 二级疲劳状态下不能机动

                if (canMoveFlag)// 如果可以机动
                {
                    if (tire_accumulate_time > 0) tire_accumulate_time = 0;// 停止消去疲劳值的倒计时
                    float percetage = (float)speed / 3.6f / (float)map.Width;
                    cur_pos += percetage;
                    if (cur_pos >= 1)  // 到达了下一格
                    {
                        cur_pos = 0;
                        cur_hex = move_path[0];// 修改位置
                        move_path.RemoveAt(0);// 修改机动路径

                        if (move_state == MoveStateType.RushLevel1 || move_state == MoveStateType.RushLevel2) tire += 1;// 如果处于冲锋状态，增加疲劳值

                        if (move_path.Count <= 0)  // 转为停止
                        {
                            speed = 0;
                            move_to_stop_remain_time = 76;// 机动转静止倒计时
                            if (tire > 0) tire_accumulate_time = 76;// 如果有疲劳值，开始消去疲劳值的倒计时（tire为2时倒计时内部会再次开始倒计时，直到tire为0
                        }
                        else
                        {
                            float basicSpeed;// 计算速度
                            if (move_state == MoveStateType.Normal)// 如果是正常机动
                            {
                                basicSpeed = basic_speed;// 正常机动速度
                            }
                            else if (move_state == MoveStateType.RushLevel1)// 如果是一级冲锋
                            {
                                basicSpeed = basic_speed * 2;// 速度翻倍
                                if (tire >= 2) tire_accumulate_time = 76;// 如果疲劳值为2，不能继续机动，开始消去疲劳值的倒计时
                            }
                            else if (move_state == MoveStateType.RushLevel2)// 如果是二级冲锋
                            {
                                basicSpeed = basic_speed * 4;// 速度为4倍
                                if (tire >= 1) tire_accumulate_time = 76;// 如果疲劳值为1，不能继续机动，开始消去疲劳值的倒计时
                            }
                            else
                            {
                                Trace.TraceWarning($"持续机动属性更新失败：算子{obj_id}机动状态有误");
                                return;
                            }
                            speed = (int)(basicSpeed / map.GetHexCosts(cur_hex / 100, cur_hex % 100, MoveMode.Walk)[move_path[0]]);// 计算速度（基础速度除通行代价）
                        }
                    }
                }
            }
            // 停止机动
            if (flag_force_stop)// 如果被停止机动
            {
                if (speed == 0)// 如果没有在机动
                {
                    if (can_to_move)// 如果可以机动（75秒停止机动倒计时结束）
                    {
                        flag_force_stop = false;// 停止机动的标志位设置为false
                    }
                }
                else if (cur_pos <= 0)// 如果正在机动，且完成了当前格机动
                {
                    if (move_path == null) move_path = new List<int>();// 清除机动路径
                    else move_path.Clear();
                    speed = 0;// 停止机动
                    move_to_stop_remain_time = 76;// 机动转停止倒计时
                    if (tire > 0 && tire_accumulate_time <= 0) tire_accumulate_time = 76;// 如果有疲劳值，开始消去疲劳值的倒计时（tire为2时倒计时内部会再次开始倒计时，直到tire为0
                    can_to_move = false;// 不可机动
                }
            }
            // 75秒倒计时
            if (move_to_stop_remain_time > 0)  // 机动转停止倒计时
            {
                move_to_stop_remain_time--;
                if (move_to_stop_remain_time <= 0)// 如果倒计时结束
                {
                    can_to_move = true;// 可以继续机动
                    flag_force_stop = false;// 停止机动的标志位设置为false
                    stop = true;// 处于静止状态
                }
            }
            if (change_state_remain_time > 0)  // 切换状态倒计时
            {
                if (keep && target_state == MoveStateType.Shelt)    //被压制，中断掩蔽
                {
                    change_state_remain_time = 0;// 结束倒计时
                    target_state = move_state;// 目标状态恢复成当前状态
                }
                else// 没被压制，则继续倒计时
                {
                    change_state_remain_time--;
                    if (change_state_remain_time <= 0)// 如果倒计时结束
                    {
                        move_state = target_state;// 机动状态设置为目标状态
                    }
                }
            }
            if (weapon_cool_time > 0)  // 武器冷却倒计时
            {
                weapon_cool_time--;
            }
            if (get_on_remain_time > 0)   //上车倒计时
            {
                if (keep)// 如果被压制
                {
                    get_on_remain_time = 0;// 结束上车倒计时
                    get_on_partner_id.Clear();// 清空
                }
                else if (get_on_partner_id.Count <= 0)  //车辆算子被压制，导致get_on_partner_id为空（GetOnAndOffMonitor方法）
                {
                    get_on_remain_time = 0;// 结束上车倒计时
                }
                else
                {
                    get_on_remain_time--;
                    if (get_on_remain_time <= 0)// 如果倒计时结束
                    {
                        car = get_on_partner_id[0];// 记录所在的车辆
                        on_board = true;// 状态为在车上
                        launcher = -1;// 取消对发射单位的记录
                        get_on_partner_id.RemoveAt(0);// 移除车辆id
                    }
                }
            }
            if (get_off_remain_time > 0)    //下车倒计时
            {
                //if (keep)
                //{
                //    get_off_remain_time = 0;
                //    get_off_partner_id.Clear();
                //}
                if (get_off_partner_id.Count <= 0)  //车辆算子被压制，导致get_off_partner_id为空（GetOnAndOffMonitor方法）
                {
                    get_off_remain_time = 0;// 结束下车倒计时
                }
                else
                {
                    get_off_remain_time--;
                    if (get_off_remain_time <= 0)// 如果倒计时结束
                    {
                        launcher = get_off_partner_id[0];// 记录车辆为发射单位
                        on_board = false;// 修改状态为不在车上
                        car = -1;// 取消对所在车辆的记录
                        get_off_partner_id.Clear();// 清空
                        //下车完成初始化机动属性
                        can_to_move = true;// 可机动
                        flag_force_stop = false;// 没有被强行停止机动
                        stop = true;// 静止
                    }
                }
            }
            if (tire_accumulate_time > 0)//疲劳倒计时
            {
                tire_accumulate_time--;
                if (tire_accumulate_time <= 0)// 如果倒计时结束
                {
                    tire -= 1;// 疲劳值减一
                    if (tire > 0) tire_accumulate_time = 75;// 如果还有疲劳值，继续倒计时（由于本次step不会再进入此方法执行减减操作，所以设为75秒
                    else tire = 0;// 否则设置为0
                }
            }
            if (keep_remain_time > 0)//压制倒计时
            {
                keep_remain_time--;
                if (keep_remain_time <= 0)// 如果倒计时结束
                {
                    keep = false;// 不再被压制
                }
            }
        }
        private void UpdataMoveAttris(IJudgeResult judge_result, Map map)
        {
            if (judge_result.ActionType != ActionType.Move)
            {
                return;
            }

            MoveJudgeResult moveJudgeResult = (MoveJudgeResult)judge_result;// 强转为机动裁决结果类型
            //修改算子属性
            float basicSpeed;// 计算速度
            if (move_state == MoveStateType.RushLevel1)// 如果是一级冲锋
            {
                basicSpeed = basic_speed * 2;// 速度翻倍
            }
            else if (move_state == MoveStateType.Normal || move_state == MoveStateType.Shelt)// 如果是正常机动或者掩蔽
            {
                basicSpeed = basic_speed;// 正常机动速度
            }
            else if (move_state == MoveStateType.RushLevel2)// 如果是二级冲锋
            {
                basicSpeed = basic_speed * 4; // 速度4倍
            }
            else
            {
                Trace.TraceWarning($"机动裁决结果更新失败：算子{obj_id}机动状态有误");
                return;
            }
            if (move_state == MoveStateType.Shelt) move_state = MoveStateType.Normal;// 如果当前状态是掩蔽状态，修改为正常机动状态
            speed = (int)(basicSpeed / map.GetHexCosts(cur_hex / 100, cur_hex % 100, MoveMode.Walk)[moveJudgeResult.MovePath[0]]);// 修改速度，基础速度除通行代价
            stop = false;// 静止标志位设置为false
            move_path = moveJudgeResult.MovePath;// 保存机动路径
            move_to_stop_remain_time = 0;// 结束机动转停止倒计时
            tire_accumulate_time = 0;// 结束消除疲劳值倒计时
        }
        private void UpdataChangeStateAttris(IJudgeResult judge_result)
        {
            if (judge_result.ActionType != ActionType.ChangeState)
            {
                return;
            }
            ChangeStateJudgeResult changeStateJudgeResult = (ChangeStateJudgeResult)judge_result;// 强转为切换状态裁决结果
            target_state = changeStateJudgeResult.TargetState;// 保存要转换的目标状态
            // 转正常机动、冲锋，不用倒计时
            if (target_state == MoveStateType.Normal || target_state == MoveStateType.RushLevel1 || target_state == MoveStateType.RushLevel2) move_state = target_state;
            else change_state_remain_time = 76;// 其他都需要75秒倒计时（76在进入倒计时代码时会减一，变成75）
        }
        private void UpdataStopMoveAttris(IJudgeResult judge_result)
        {
            if (judge_result.ActionType != ActionType.StopMove)
            {
                return;
            }
            flag_force_stop = true;// 停止机动标志位设置为true
        }
        private void UpdataGetOnAttris(IJudgeResult judge_result)
        {
            if (judge_result.ActionType != ActionType.GetOn) return;

            GetOnJudgeResult getOnJudgeResult = (GetOnJudgeResult)judge_result;// 强转为上车裁决结果类型
            get_on_partner_id.Add(getOnJudgeResult.TargetObjID);// 添加上车的目标车辆算子id
            get_on_remain_time = 76;// 上车倒计时
        }
        private void UpdataShootAttris(IJudgeResult judge_result)
        {
            JudgeType type = (JudgeType)judge_result.GetType().GetProperty("Type").GetValue(judge_result);// 取得裁决类型
            // 攻击，即直瞄
            if (judge_result.ObjID == obj_id && type == JudgeType.Shoot)// 如果是直瞄射击，且是本算子执行的（不考虑是否裁决成功）
            {
                ShootingJudgeResult shootingJudgeResult = (ShootingJudgeResult)judge_result;// 强转为直瞄射击裁决结果类型

                remain_bullet_nums[shootingJudgeResult.BulletType]--;// 减去子弹数目
                weapon_cool_time = 76;// 武器冷却
                if (move_state == MoveStateType.Shelt)// 如果算子正在掩蔽
                {
                    move_state = MoveStateType.Normal;// 取消掩蔽状态
                }                
            }
            // 引导射击
            else if (judge_result.ObjID == obj_id && type == JudgeType.GuidedShoot)// 如果是引导射击，且是本算子执行的（不考虑是否裁决成功）
            {
                weapon_cool_time = 76;// 引导射击75秒倒计时
            }
            else 
            {
                // 被攻击
                if (!judge_result.IsSuccess) return;// 不成功，跳过

                int damage = (int)judge_result.GetType().GetProperty("Damage").GetValue(judge_result);
                int targetObjID = (int)judge_result.GetType().GetProperty("TargetObjID").GetValue(judge_result);
                if (!on_board && targetObjID == obj_id)// 本算子是被攻击的
                {
                    if (blood > damage)// 如果生命值大于伤害值
                    {
                        if (damage == 0)// 如果是纯压制
                        {
                            if (keep)// 如果已经处于压制状态
                            {
                                blood -= 1;// 失去一点生命值
                            }
                            else// 如果没有被压制
                            {
                                keep = true;// 被压制
                            }
                            keep_remain_time = 151;// 设置150秒压制倒计时
                        }
                        else
                        {
                            blood -= damage;// 扣去
                            keep = true;// 被压制
                            keep_remain_time = 151;// 压制倒计时
                        }

                        if (change_state_remain_time > 0 && target_state == MoveStateType.Shelt)//被压制，中断掩蔽
                        {
                            change_state_remain_time = 0;// 结束切换状态倒计时
                            target_state = move_state;// 目标状态恢复成当前状态
                        }
                        if (get_on_remain_time > 0)//被压制，中断上车
                        {
                            get_on_remain_time = 0;// 中断倒计时
                            get_on_partner_id.Clear();// 清空
                        }
                    }
                    else blood = 0;// 如果生命值小于等于伤害值，生命值归零
                }
                else if (on_board && targetObjID == car)// 如果在车辆上，且车辆算子被攻击了
                {
                    if (blood > damage)// 如果生命值大于伤害值
                    {
                        blood -= damage;// 扣去
                    }
                    else blood = 0;// 如果生命值小于等于伤害值，生命值归零
                }
            }
        }
        private void UpdataGetOffAttris(IJudgeResult judge_result)
        {
            if (judge_result.ActionType != ActionType.GetOff) return;

            GetOffJudgeResult getOffJudgeResult = (GetOffJudgeResult)judge_result;// 强转为下车裁决结果类型
            if (getOffJudgeResult.TargetObjID != obj_id) return;// 如果下车的对象不是本算子，跳过
            get_off_partner_id.Add(getOffJudgeResult.ObjID);// 添加下车对象为车辆算子 （ ObjID为动作主体，即车辆算子
            get_off_remain_time = 76;// 下车倒计时
            cur_hex = getOffJudgeResult.CurHex;// 修改算子位置为车辆位置
        }
        private void UpdataStackAttris(List<IOperator> oprs)
        {
            int stack_count = 0;// 记录本算子当前所在的六角格一共有多少算子
            for (int i = 0; i < oprs.Count; i++)
            {
                if (!typeof(IMoveAttris).IsAssignableFrom(oprs[i].GetType())) continue;// 没有cur_hex属性，跳过

                int other_hex = (int)oprs[i].GetType().GetProperty("CurHex").GetValue(oprs[i]);
                if (cur_hex == other_hex)// 如果在同一个六角格
                {
                    Color other_color = (Color)oprs[i].GetType().GetProperty("Color").GetValue(oprs[i]);// 颜色
                    OprType other_type = (OprType)oprs[i].GetType().GetProperty("Type").GetValue(oprs[i]);// 细分类型
                    if (color == other_color && (other_type == OprType.Vehicle || other_type == OprType.Infantry)) stack_count++;// 如果是己方地面算子，stack_count加一
                }
            }
            if (stack_count > 1) stack = true;// 如果有己方其他地面算子，则为堆叠状态
            else stack = false;// 否则不为堆叠
        }
        private void UpdataSeeEnemyAttris(List<IOperator> oprs, Map map)
        {
            if (observe_distance == null) return;// 如果观察距离属性为空，不作判断

            if (see_enemy_bop_ids == null) see_enemy_bop_ids = new List<int>();// 初始化see_enemy_bop_ids
            else see_enemy_bop_ids.Clear();
            for (int i = 0; i < oprs.Count; i++)
            {
                if (!typeof(ICommonAttris).IsAssignableFrom(oprs[i].GetType()) ||
                    !typeof(IMoveAttris).IsAssignableFrom(oprs[i].GetType())) continue;// 没有必要的属性，跳过

                Color enemy_color = (Color)oprs[i].GetType().GetProperty("Color").GetValue(oprs[i]);
                OprType enemy_type = (OprType)oprs[i].GetType().GetProperty("Type").GetValue(oprs[i]);
                int enemy_hex = (int)oprs[i].GetType().GetProperty("CurHex").GetValue(oprs[i]);
                OprSubType enemy_sub_type = (OprSubType)oprs[i].GetType().GetProperty("Subtype").GetValue(oprs[i]);
                MoveStateType enemy_move_state = (MoveStateType)oprs[i].GetType().GetProperty("MoveState").GetValue(oprs[i]);

                if (color == enemy_color) continue;// 己方算子，跳过

                if (map.CanSeeTerrain(type, enemy_type, cur_hex, enemy_hex, enemy_sub_type, observe_distance, enemy_move_state))// 可以看见
                {
                    see_enemy_bop_ids.Add(oprs[i].ObjID);// 将此算子id加进see_enemy_bop_ids
                }
            }
        }
        private void JudgeMoveObstruction(List<IOperator> oprs)
        {
            if (speed > 0 && move_path.Count > 0)// 如果正在机动
            {
                int nextHexStackCount = 0;// 记录机动的下一个六角格有多少算子
                foreach (IOperator op in oprs)// 遍历态势中的算子
                {
                    if (!typeof(IMoveAttris).IsAssignableFrom(op.GetType()) || !typeof(ICommonAttris).IsAssignableFrom(op.GetType())) continue;// 没有机动相关属性
                    //是否在下一格
                    int opHex = (int)op.GetType().GetProperty("CurHex").GetValue(op);// 获取遍历到的算子的位置
                    if (opHex != move_path[0]) continue;// 不在下一格，跳过
                    //是否是地面算子
                    OprType opType = (OprType)op.GetType().GetProperty("Type").GetValue(op);
                    if (opType == OprType.Vehicle || opType == OprType.Infantry)// 如果是地面算子
                    {
                        //堆叠4个阻塞判断
                        Color opColor = (Color)op.GetType().GetProperty("Color").GetValue(op);
                        if (color == opColor) nextHexStackCount++;// 如果遍历到的算子是己方算子，记录
                    }
                }
                //六角格内已存在4个本方地面单位，则格外本方地面单位不能再进入或通过该六角格。
                if (nextHexStackCount >= 4)
                {
                    cur_pos = 0;// 阻塞，本算子不可继续向下一格机动
                }
            }
        }
        private void GetOnAndOffMonitor(List<IOperator> oprs)
        {
            //上车时检测车辆算子是否被压制 或者移动
            if (get_on_partner_id == null) get_on_partner_id = new List<int>();
            if (get_on_partner_id.Count > 0 && get_on_remain_time > 0)// 如果正在上车
            {
                foreach (IOperator op in oprs)// 遍历态势中的算子
                {
                    if (get_on_partner_id.Contains(op.ObjID))// 在态势中找到了等待上车的算子
                    {
                        if (!typeof(IMoveAttris).IsAssignableFrom(op.GetType()) || !typeof(ICommonAttris).IsAssignableFrom(op.GetType())) continue;// 没有具备相关属性，跳过

                        bool opKeep = (bool)op.GetType().GetProperty("Keep").GetValue(op);
                        // 避免同时给车辆下达机动命令，步兵下达上车命令，逃过裁决时的判断
                        bool stop = (bool)op.GetType().GetProperty("Stop").GetValue(op);
                        if (opKeep || !stop)// 如果遍历到的算子被压制或者开始机动了（同一个step对步兵和战车分别下达了上车和机动动作，会出现战车机动的情况）
                        {
                            get_on_partner_id.Remove(op.ObjID);// 中断上车，从等待上车算子的列表中移除
                        }
                    }
                }
            }
            //下车时检测车辆算子是否被压制
            if (get_off_partner_id == null) get_off_partner_id = new List<int>();
            if (get_off_partner_id.Count > 0 && get_off_remain_time > 0)// 如果正在下车
            {
                foreach (IOperator op in oprs)// 遍历算子
                {
                    if (get_off_partner_id.Contains(op.ObjID))// 如果在态势中找到了车辆算子
                    {
                        if (!typeof(IMoveAttris).IsAssignableFrom(op.GetType()) || !typeof(ICommonAttris).IsAssignableFrom(op.GetType())) continue;// 没有具备相关属性，跳过

                        bool opKeep = (bool)op.GetType().GetProperty("Keep").GetValue(op);
                        if (opKeep)// 如果车辆被压制
                        {
                            get_off_partner_id.Remove(op.ObjID);// 中断上车
                        }
                    }
                }
            }
        }
    }
}
